/**
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */
import { DatePickerProps } from "../date-picker.props";
import { DateObject, Period } from "../types/common";
import { ref } from 'vue';
import { DateFormatInfo, UseNormalizeDate } from "./types";
import { useDateFormat } from "./use-date-format";
import { useNumber } from "./use-number";
import { useCompare } from "./use-compare";
import { NameOfMonths } from "../types/month";
import { useDisableDate } from "./use-disable-date";

export function useNormalizeDate(props: DatePickerProps): UseNormalizeDate {

    const { displayFormat, minYear, maxYear, selectMode, valueFormat, displayTime, periodDelimiter } = props;
    const { getDateValue } = useDateFormat();
    const { getNumberByValue, getMonthNumberByMonthName } = useNumber();
    const { equalOrEarlier, isInitializedDate } = useCompare();
    const { isDisabledDate } = useDisableDate(
        props.minYear,
        props.maxYear,
        props.disableSince,
        props.disableUntil,
        props.disableDates,
        props.disablePeriod,
        props.disableWeekends,
        props.disableWeekdays
    );

    const nameOfMonths = ref<NameOfMonths>(props.nameOfMonths);
    const daysInMonth: Array<number> = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

    function normalizeInputDate(dateString: string, useValueFormat = false) {
        let shouldDisplayTime = displayTime;
        let actualFormat = displayFormat;
        let targetDateString = dateString;
        if (useValueFormat) {
            actualFormat = valueFormat.replace(/[年,月]/g, '-').replace(/[日]/, '').replace(/[时,分]/g, ':').replace(/[秒]/g, '');
            targetDateString = targetDateString.replace(/[年,月]/g, '-').replace(/[日]/, '').replace(/[时,分]/g, ':').replace(/[秒]/g, '');
            if (targetDateString[targetDateString.length - 1] === '-' || targetDateString[targetDateString.length - 1] === ':') {
                targetDateString = targetDateString.substring(0, targetDateString.length - 1);
            }
            if (!displayTime && valueFormat.toLocaleLowerCase().indexOf('hh:mm') > -1) {
                shouldDisplayTime = true;
            }
        }
        return { actualFormat, shouldDisplayTime, targetDateString };
    }

    function normalizeDate(dateString: string, useValueFormat = false): DateObject {
        const normalizedDate = { year: 0, month: 0, day: 0 };
        if (!dateString) {
            return normalizedDate;
        }

        const { actualFormat, shouldDisplayTime, targetDateString } = normalizeInputDate(dateString, useValueFormat);
        const isFromMonthString: boolean = actualFormat.indexOf('MMM') !== -1;
        let normalizedDateString = targetDateString;
        let hour = 0;
        let minute = 0;
        let second = 0;
        let delimeters = actualFormat.match(/[^(DdMmYy)]{1,}/g) as string[] | null;

        if (shouldDisplayTime && targetDateString) {
            normalizedDateString = targetDateString.split(' ')[0];
            Object.assign(normalizedDate, { hour: 0, minute: 0, second: 0 });
            const timeStr = targetDateString.split(' ')[1];
            if (timeStr) {
                const _timer = timeStr.replace('时', ':').replace('分', ':').replace('秒', '').split(':');
                if (_timer[0]) {
                    hour = Number(_timer[0].substr(0, 2));
                    hour = isNaN(hour) ? 0 : hour;
                }
                if (_timer[1]) {
                    minute = Number(_timer[1].substr(0, 2));
                    minute = isNaN(minute) ? 0 : minute;
                }

                if (_timer[2]) {
                    second = Number(_timer[2].substr(0, 2));
                    second = isNaN(second) ? 0 : second;
                }
            } else {
                delimeters = null;
                const reg = /^\d{1,}$/;
                if (reg.test(targetDateString)) { // 验证传入的格式为 yyyyMMddHHmmss
                    const df = actualFormat;
                    normalizedDateString = targetDateString.substr(0, 8);
                    let _timer = targetDateString.substr(8);
                    if (_timer) {
                        if (df.includes('HH')) {
                            if (_timer) {
                                hour = +_timer.slice(0, 2);
                                _timer = _timer.slice(2);
                            }
                        }
                        if (df.includes('mm')) {
                            if (_timer) {
                                minute = +_timer.slice(0, 2);
                                _timer = _timer.slice(2);
                            }
                        }
                        if (df.includes('ss')) {
                            if (_timer) {
                                second = +_timer.slice(0, 2);
                            }
                        }
                    }
                }
            }
        } else {
            normalizedDateString = targetDateString ? targetDateString.split(' ')[0] : '';
        }

        const dateValue: DateFormatInfo[] = getDateValue(normalizedDateString, actualFormat, delimeters);

        const year: number = getNumberByValue(dateValue[0]);
        const month: number = isFromMonthString
            ? getMonthNumberByMonthName(dateValue[1], nameOfMonths.value)
            : getNumberByValue(dateValue[1]);
        const day: number = getNumberByValue(dateValue[2]);

        if (selectMode === 'year') {
            return { year, month: 1, day: 1 };
        }

        if (month !== -1 && day !== -1 && year !== -1) {
            if (year < minYear || year > maxYear || month < 1 || month > 12) {
                return normalizedDate;
            }
            const date: DateObject = displayTime ? { year, month, day, hour, minute, second } : { year, month, day };

            if (isDisabledDate(date)) {
                return normalizedDate;
            }

            if (year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0)) {
                daysInMonth[1] = 29;
            }

            if (day < 1 || day > daysInMonth[month - 1]) {
                return normalizedDate;
            }

            // Valid date
            if (selectMode === 'month') {
                return { year: date.year, month: date.month };
            }
            if (selectMode === 'year') {
                return { year: date.year };
            }
            return date;
        }

        return normalizedDate;
    }

    function normalizeDateRange(dateRangeStr: string): Period {
        let period: Period = {
            from: { year: 0, month: 0, day: 0 },
            to: { year: 0, month: 0, day: 0 }
        };
        if (dateRangeStr && dateRangeStr.length) {
            const dates: Array<string> = dateRangeStr.split(periodDelimiter);
            if (dates && dates.length === 2) {
                const [fromDate, toDate] = dates;
                const from: DateObject = normalizeDate(fromDate, true);
                if (isInitializedDate(from)) {
                    const to: DateObject = normalizeDate(toDate, true);
                    if (isInitializedDate(to) && equalOrEarlier(from, to)) {
                        period = { from, to };
                    }
                }
            }
        }
        return period;
    }

    return { normalizeDate };
}
